import {DcVectorLayerOptions} from '../entity/dc-vector-layer-options';
import {Injector} from '@angular/core';
import VectorImageLayer from 'ol/layer/VectorImage';
import VectorSource from 'ol/source/Vector';
import {bbox} from 'ol/loadingstrategy';
import {DcVectorLayerQueryOptions} from '../entity/dc-vector-layer-query-options';
import Projection from 'ol/proj/Projection';
import Feature from 'ol/Feature';
import Layer from 'ol/layer/Layer';
import MapBrowserEvent from 'ol/MapBrowserEvent';
import Style from 'ol/style/Style';
import {Extent} from 'ol/extent';
import {fromExtent} from 'ol/geom/Polygon';
import {DcVectorLayerOperateService} from '../service/dc-vector-layer-operate.service';
import {NzMessageService} from 'ng-zorro-antd';
import {DcFeature} from '../entity/dc-feature';
import WKT from 'ol/format/WKT';
import Stroke from 'ol/style/Stroke';
import Fill from 'ol/style/Fill';
import Geometry from 'ol/geom/Geometry';
import {ISbBaseLayer} from './ISbBaseLayer';

export class SbVectorLayer extends VectorImageLayer implements ISbBaseLayer {
    private vectorLayerOperateService: DcVectorLayerOperateService;

    private message: NzMessageService;
    private _lastRequestIndex = 0;
    private _minRequestIndex = 0;
    private _defaultStyle: Style = new Style({
        stroke: new Stroke({
            color: '#f00',
            width: 1,
        }),
        fill: new Fill({
            color: 'rgba(255,0,0,0.1)',
        }),
    });
    private wktFormat = new WKT();

    constructor(private sbLayerOptions: DcVectorLayerOptions, private inject?: Injector) {
        super(sbLayerOptions);

        this.vectorLayerOperateService = inject.get(DcVectorLayerOperateService);

        this.message = inject.get(NzMessageService);

        this.init();
    }

    private _sourceChangeCallback: (source: VectorSource) => void;

    get sourceChangeCallback(): (source: VectorSource) => void {
        return this._sourceChangeCallback;
    }

    set sourceChangeCallback(value: (source: VectorSource) => void) {
        this._sourceChangeCallback = value;
    }

    private _beforeLoadParamCallback: (param: DcVectorLayerQueryOptions, extent: Extent, resolution: number, projection: Projection) => DcVectorLayerQueryOptions;

    get beforeLoadParamCallback(): (param: DcVectorLayerQueryOptions, extent: Extent, resolution: number, projection: Projection) => DcVectorLayerQueryOptions {
        return this._beforeLoadParamCallback;
    }

    set beforeLoadParamCallback(value: (param: DcVectorLayerQueryOptions, extent: Extent, resolution: number, projection: Projection) => DcVectorLayerQueryOptions) {
        this._beforeLoadParamCallback = value;
    }

    private _featureClickCallback: (feature: Feature, layer: Layer, mapEvent: MapBrowserEvent) => void;

    get featureClickCallback(): (feature: Feature, layer: Layer, mapEvent: MapBrowserEvent) => void {
        return this._featureClickCallback;
    }

    set featureClickCallback(value: (feature: Feature, layer: Layer, mapEvent: MapBrowserEvent) => void) {
        this._featureClickCallback = value;
    }

    private _featurePointermoveCallback: (feature: Feature, layer: Layer, mapEvent: MapBrowserEvent) => void;

    get featurePointermoveCallback(): (feature: Feature, layer: Layer, mapEvent: MapBrowserEvent) => void {
        return this._featurePointermoveCallback;
    }

    set featurePointermoveCallback(value: (feature: Feature, layer: Layer, mapEvent: MapBrowserEvent) => void) {
        this._featurePointermoveCallback = value;
    }

    private _styleCallback: (feature: Feature, resolution: number, styles: Style[]) => Style[];

    get styleCallback(): (feature: Feature, resolution: number, styles: Style[]) => Style[] {
        return this._styleCallback;
    }

    set styleCallback(value: (feature: Feature, resolution: number, styles: Style[]) => Style[]) {
        this._styleCallback = value;
    }

    get keyName() {
        return 'id';
    }

    get geometryName() {
        return 'shape';
    }

    get layerId() {
        return this.sbLayerOptions.layerId;
    }

    get source() {
        return this.getSource() as VectorSource;
    }

    featureClick(feature: Feature, layer: Layer, mapEvent: MapBrowserEvent): void {
        if (this.featureClickCallback) {
            this.featureClickCallback(feature, this, mapEvent);
        }
    }

    featurePointermove(feature: Feature, layer: Layer, mapEvent: MapBrowserEvent): void {
        if (this.featurePointermoveCallback) {
            this.featurePointermoveCallback(feature, this, mapEvent);
        }
    }

    sourceChange(source: VectorSource): void {
    }

    private init() {

        this.sourceChangeCallback = this.sbLayerOptions.sourceChangeCallback;
        this.beforeLoadParamCallback = this.sbLayerOptions.beforeLoadParamCallback;
        this.featureClickCallback = this.sbLayerOptions.featureClickCallback;
        this.featurePointermoveCallback = this.sbLayerOptions.featurePointermoveCallback;
        this.styleCallback = this.sbLayerOptions.styleCallback;

        if (!this.getSource()) {
            const source = new VectorSource({
                strategy: bbox,
                loader: this.loader.bind(this),
                useSpatialIndex: true,
                wrapX: true
            });
            this.setSource(source);
        }

        // if (!this.getStyle()) {
        this.setStyle(this.styleLoader.bind(this));
        // }
    }

    private styleLoader(feature: Feature, resolution: number): Style | Style[] {
        let style: Style[] = [this._defaultStyle];
        if (this.styleCallback) {
            style = this.styleCallback(feature, resolution, style);
        } else {

        }
        return style;
    }

    private loader(extent: Extent, resolution: number, projection: Projection): void {
        const _lastRequestIndex = this._lastRequestIndex++;
        if (Number.isNaN(extent[0])) {
            return;
        }
        let g: Geometry = fromExtent(extent);
        g = g.transform('EPSG:3857', 'EPSG:4326');
        const geometry = this.wktFormat.writeGeometry(g);
        let param = {
            geometry: geometry,
            layerId: this.layerId,
            returnTotal: false,
            returnGeometry: true
        } as DcVectorLayerQueryOptions;

        // 添加字段
        // var queryFields = [data.geometryName];
        // if (data.labelField) {
        //     queryFields.push(data.labelField)
        // }
        // param.queryFields = queryFields;

        // 添加分组样式
        // if (that._sbMapParam.getLayerConfigById(data.id).customStyleTemp) {
        //     // sbLayerDataQuery.queryByExtent(data.id,extent,function(returnFeatures){
        //     var customStyle = that._sbMapParam.getLayerConfigById(data.id).customStyleTemp;
        //     queryFields.push(customStyle.field);
        //     p.queryObjects = that._sbMapParam.getGroupWhere(data.id);
        // }

        if (this.beforeLoadParamCallback) {
            param = this.beforeLoadParamCallback(param, extent, resolution, projection);
            if (!param) {
                this.message.info('自定义参数存在问题');
                return;
            }
        }

        this.vectorLayerOperateService.query(this.layerId, param).subscribe(result => {
            if (this._minRequestIndex > _lastRequestIndex) {
                return true;
            }
            if (result.success) {
                const returnFeatures = this.changeToFeature(result.message.rows);
                const addFeatures = [];
                for (const feature of returnFeatures) {
                    const f = this.source.getFeatureById(feature.getId());
                    if (!f) {
                        addFeatures.push(feature);
                    }
                }
                this.source.addFeatures(addFeatures);
            }
        });
    }

    private changeToFeature(dcFeatures: DcFeature[]): Feature[] {
        const olFeatures = [];
        for (const dcFeature of dcFeatures) {
            const key = dcFeature[this.keyName];
            let wkt = dcFeature[this.geometryName];

            delete dcFeature[this.geometryName];

            const olFeature = new Feature();
            olFeature.setId(key);
            olFeature.setProperties(dcFeature);
            let geometry: Geometry;
            try {
                if (wkt.indexOf('Z') >= 0 || wkt.indexOf('M') >= 0) {
                    wkt = wkt.replace(/(ZM|Z|M)(\s)*\(/, '(');
                    let newWkt = '';
                    let temp = '';
                    for (let j = 0; j < wkt.length; j++) {
                        if (wkt[j] === '(' || wkt[j] === ')' || wkt[j] === ',') {
                            // 处理temp;
                            const r = temp.trim().split(' ');
                            if (r.length === 4 || r.length === 3) {
                                temp = r[0] + ' ' + r[1];
                            }
                            newWkt += temp;
                            temp = '';
                            newWkt += wkt[j];
                        } else {
                            temp += wkt[j];
                        }
                    }
                    wkt = newWkt;
                }
                geometry = this.wktFormat.readGeometry(wkt);
            } catch (e) {
                geometry = undefined;
            }
            if (geometry) {
                geometry = geometry.transform('EPSG:4326', 'EPSG:3857');
            }
            olFeature.setGeometry(geometry);
            olFeatures.push(olFeature);
        }
        return olFeatures;
    }
}
